//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
namespace LargoCommon.Music
{
///
/// Rhythmic Container.
///
public class RhythmicContainer {
#region Fields
///
/// Singleton variable.
///
private static readonly RhythmicContainer InternalSingleton = new RhythmicContainer();
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The given rhythmic structures.
public RhythmicContainer(IEnumerable givenRhythmicStructures) {
Contract.Requires(givenRhythmicStructures != null);
this.RhythmicStructures = givenRhythmicStructures;
}
///
/// Prevents a default instance of the RhythmicContainer class from being created.
///
private RhythmicContainer() {
}
#endregion
#region Static properties
///
/// Gets the ProcessLogger Singleton.
///
/// Property description. ///
public static RhythmicContainer Singleton {
get {
Contract.Ensures(Contract.Result() != null);
if (InternalSingleton == null) {
throw new InvalidOperationException("Singleton Rhythmic Container is null.");
}
return InternalSingleton;
}
}
#endregion
#region Public properties
///
/// Gets the rhythmic structures.
///
///
/// The rhythmic structures.
///
public IEnumerable RhythmicStructures { get; }
///
/// Gets or sets the rhythm of harmony structures.
///
///
/// The rhythm of harmony structures.
///
[UsedImplicitly]
public IList RhythmicOfHarmonyStructures { get; set; } //// CA1044 (FxCop)
#endregion
#region Private properties
/*
///
/// Gets all variant structures.
///
/// Property description.
private IList AllVariantStructures {
get {
//// return null;
///// Rhythmic structures ...
var structs = RegularStructures(this.rhythmicOrder).ToList();
structs.AddRange(this.Structures);
structs.AddRange(this.RhythmicOfHarmonyStructures);
var sortedStructs = (from str in structs
orderby str.Mobility ascending, str.ElementSchema descending
where str != null
select str).Distinct().ToList();
return sortedStructs;
}
}
///
/// Gets the common structures.
///
/// Property description.
private IList CommonStructures {
get {
var structs = this.SegmentOfStructures(3, 0);
return structs;
}
}
///
/// Gets the mean structures.
///
/// Property description.
private IList MeanStructures {
get {
var structs = this.SegmentOfStructures(3, 1);
return structs;
}
}
///
/// Gets the rare structures.
///
/// Property description.
private IList RareStructures {
get {
var structs = this.SegmentOfStructures(3, 2);
return structs;
}
}
///
/// Gets or sets the structures.
///
///
/// The structures.
///
private IList Structures { get; set; }
*/
#endregion
#region Static methods
///
/// Gets the regular structures.
///
/// The given rhythmic order.
///
/// Returns value.
///
/// Property description.
public static IList RegularStructures(byte givenRhythmicOrder)
{
var structs = new List();
for (var parts = 1; parts < givenRhythmicOrder - 1; parts++)
{
if (parts > 16 || givenRhythmicOrder % parts != 0)
{
continue;
}
var rms = RegularRhythmicStructure(givenRhythmicOrder, parts);
structs.Add(rms);
}
return structs;
}
#endregion
/// Gets grouped rhythmic structures.
/// The given model.
/// The given block.
/// The grouped rhythmic structures.
public IList GetGroupedRhythmicStructures(RhythmicModel givenModel, MusicalBlock givenBlock) {
var rhythmicMaterial = givenModel.ExtractRhythmicMaterial();
var list = (from s in rhythmicMaterial.Structures
orderby s.ToneLevel descending, s.FormalBehavior.Variance ascending, s.Occurrence descending
select s).ToList();
//// Regular structures.
var regular = RegularStructures(givenModel.RhythmicOrder); //// Header.System.RhythmicOrder
list.AddRange(regular);
//// Structures from harmony.
if (givenBlock != null) {
var tmplist = new List();
foreach (var bar in givenBlock.Body.Bars) {
var structure = bar?.HarmonicBar?.RhythmicStructure;
if (structure == null) {
continue;
}
tmplist.Add(structure);
}
list.AddRange(tmplist);
}
//// Grouping
IList structures = new List();
var groupList = (from ms in list
group ms by ms.GetStructuralCode into g
select g).ToList();
foreach (var g in groupList) {
var s = g.FirstOrDefault();
if (s == null) {
continue;
}
var ms = s; //// Clone? //// new RhythmicStructure(s.RhythmicSystem, s.GetStructuralCode())
ms.Occurrence = g.Count();
ms.DetermineLevel(); //// 2019/01
ms.DetermineBehavior(); //// 2019/01
structures.Add(ms);
}
return structures;
}
#region Public methods - Find rhythmic structures
///
/// Rhythmic structure.
///
/// The energy change.
///
/// Returns value.
///
[UsedImplicitly]
public RhythmicStructure FindRhythmicStructure(EnergyChange energyChange) {
RhythmicStructure optimalStructure = null;
float bestValue = +10000;
foreach (var structure in this.RhythmicStructures) {
var value = Math.Abs(structure.Level - energyChange.BeatLevel)
+ Math.Abs(structure.ToneLevel - energyChange.ToneLevel)
+ Math.Abs(structure.FormalBehavior.Variance - energyChange.RhythmicTension);
if (value >= bestValue) {
continue;
}
bestValue = value;
optimalStructure = structure;
}
return optimalStructure;
}
///
/// Finds the similar structure.
///
/// The given struct.
///
/// Returns value.
///
[UsedImplicitly]
public RhythmicStructure FindSimilarStructure(RhythmicStructure givenStruct) {
Contract.Requires(givenStruct != null);
RhythmicStructure optimalStruct = null;
float minimumResult = 1000;
//// rstruct.DetermineBehavior();
foreach (var rstruct in this.RhythmicStructures) { //// 1000
if (rstruct.ElementSchema == givenStruct.ElementSchema) {
continue;
}
var s = rstruct.SimilarityValue(givenStruct);
if (s > 90) {
continue;
}
var level = givenStruct.Level + rstruct.Level > 0 ?
100.0f * 2 * Math.Abs(givenStruct.Level - rstruct.Level) / (givenStruct.Level + rstruct.Level)
: 0;
var toneLevel = givenStruct.ToneLevel + rstruct.ToneLevel > 0 ?
100.0f * 2 * Math.Abs(givenStruct.ToneLevel - rstruct.ToneLevel) / (givenStruct.ToneLevel + rstruct.ToneLevel)
: 0;
var variance = Math.Abs(givenStruct.FormalBehavior.Variance - rstruct.FormalBehavior.Variance);
var balance = Math.Abs(givenStruct.FormalBehavior.Balance - rstruct.FormalBehavior.Balance);
//// float beat = Math.Abs(givenStruct.Beat - rstruct.Beat);
//// float filling = Math.Abs(givenStruct.Filling - rstruct.Filling);
//// float complexity = Math.Abs(givenStruct.Complexity - rstruct.Complexity);
var result = (4 * toneLevel) + (2 * level) + variance + balance;
if (result >= minimumResult) {
continue;
}
optimalStruct = rstruct;
minimumResult = result;
}
return optimalStruct;
}
#endregion
#region String representation
/// String representation of the object.
/// Returns value.
public override string ToString() {
return "RhythmicContainer";
}
#endregion
#region Public methods
///
/// Gets the structures.
///
///
/// Returns value.
///
public IEnumerable GetStructures() {
return null;
/* Rhythmic structures ...
var structures = new List();
switch (listIndex) {
case 0: {
structures = (List)this.AllVariantStructures;
break;
}
case 1: {
structures = (List)this.CommonStructures;
break;
}
case 2: {
structures = (List)this.MeanStructures;
break;
}
case 3: {
structures = (List)this.RareStructures;
break;
}
case 4: {
structures = (List)RegularStructures(this.rhythmicOrder);
break;
}
case 5: {
structures = (List)this.RhythmicOfHarmonyStructures;
break;
}
}
if (structures == null) {
return null;
}
var distinctList = structures
.GroupBy(s => s.ElementSchema)
.Select(g => g.First())
.ToList();
var sortedList = (from s in distinctList
orderby s.Level, s.ToneLevel
select s).ToList();
return sortedList; */
}
///
/// Prepares the rhythmic structures.
///
/// The total number.
/// If set to true [include inversions].
///
/// Returns value.
///
[UsedImplicitly]
public IList LeadingStructures(int totalNumber, bool includeInversions) {
var structures = new List();
/*
var number = 0;
var commonStructs = LeadingStructures(totalNumber, includeInversions, this.CommonStructures, ref number);
structures.AddRange(commonStructs);
var meanStructs = LeadingStructures(totalNumber, includeInversions, this.MeanStructures, ref number);
structures.AddRange(meanStructs);
*/
return structures;
}
#endregion
#region Private static methods - Regular structures
///
/// Regulars the rhythmic structure.
///
/// The given rhythmic order.
/// The parts.
///
/// Returns value.
///
private static RhythmicStructure RegularRhythmicStructure(byte givenRhythmicOrder, int parts)
{
var rs = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Structure, givenRhythmicOrder);
var sb = new StringBuilder();
var length = givenRhythmicOrder / parts;
var s = string.Format(CultureInfo.CurrentCulture, "1,{0}*0,", length - 1);
for (var i = 0; i < parts; i++) {
sb.Append(s);
}
sb.Remove(sb.Length - 1, 1);
var rms = new RhythmicStructure(rs, sb.ToString());
return rms;
}
#endregion
#region Private methods
/*
///
/// Leading structures.
///
/// The total number.
/// If set to true [include inversions].
/// The common.
/// The number.
/// Returns value.
private static IEnumerable LeadingStructures(int totalNumber, bool includeInversions, IList common, ref int number) {
var structures = new List();
structures.AddRange(common.Take(number));
number += structures.Count;
foreach (var rstruct in common) {
// ReSharper disable once InvertIf
if (includeInversions) {
var invertedStructure = rstruct.InvertedStructure();
structures.Add(invertedStructure);
if (number >= totalNumber) {
break;
}
}
}
return structures;
}
///
/// Segments the of structures.
///
/// The class count.
/// The class number.
/// Returns value.
private List SegmentOfStructures(int classCount, int classNumber) {
var modelStructs = this.Structures;
var cnt = modelStructs.Count;
var number = (int)(1.0f * cnt / classCount);
var start = number * classNumber;
var structs = (from str in modelStructs
orderby str.Occurrence descending, str.Level ascending, str.ToneLevel ascending
select str)
.Skip(start)
.Take(number).ToList();
return structs;
} */
#endregion
}
}